home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Contributed / SpriteWorld / SpriteWorld Files / BlitPixie / Sources / BlitPixieRect.c < prev    next >
Encoding:
Text File  |  2000-10-06  |  13.1 KB  |  646 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. //    BlitPixieRect - a fast software blitter
  3. //
  4. //        Based on (but completely rewritten) the old BlitPixie routines by :
  5. //            Tony Myles, Brian Roddy, Christofer Åkersten, Tom Bishop, 
  6. //            Ben Sharpe, Brigham Stevens, Sean Callahan, Joe Britt and Tim Collins
  7. //
  8. //    written by Anders F Björklund <afb@algonet.se>
  9. //    © 1999 afb.
  10. ///--------------------------------------------------------------------------------------
  11.  
  12. #ifndef __BLITPIXIE__
  13. #include "BlitPixieHeader.h"
  14. #endif
  15.  
  16. #include "BlitPixieAsm.h"
  17.  
  18. #define USE_GENERIC_CACHE    0                        // whether to even compile the PPC cache instructions ?
  19.  
  20. #if USE_GENERIC_CACHE
  21. Boolean                gBPCacheable = false;    // destination memory cachable ? (that is: not in VRAM)        
  22. #endif
  23.  
  24. #pragma mark *** PowerPC asm:
  25. #if USE_PPC_ASSEMBLY
  26.  
  27. ///--------------------------------------------------------------------------------------
  28. //    BlitPixieRect
  29. ///--------------------------------------------------------------------------------------
  30.  
  31. //    NOTE:    assumes bytes, rows > 0 (otherwise overflow)
  32.  
  33. //    NOTE:    assumes srcRowBytes & dstRowBytes are multiples of 4 (for alignment purposes)
  34.  
  35. //    the PPC blitter is actually 3 in 1:
  36. //    • one using doubles, for wordaligned blits
  37. //      (this one is always used on PPC 601, which can blit unaligned doubles too)
  38. //    • one using words, for unaligned blits
  39. //      (un-wordaligned doubles causes alignment exceptions on everything but 601)
  40. //    • one for narrow strips, up to 32 bytes wide
  41.  
  42. ASM_FUNC void BlitPixieRect(
  43.     register unsigned char *srcPixelPTemp,                // r3
  44.     register unsigned char *dstPixelPTemp,                // r4
  45.     register unsigned long srcOffset,                    // r5
  46.     register unsigned long dstOffset,                    // r6
  47.     register unsigned short numBytesPerRow,                // r7
  48.     register unsigned short rowsToCopy)                    // r8
  49. {
  50. #define    r_srcRowBytes        r5
  51. #define    r_dstRowBytes        r6
  52. #define    r_width                r7
  53. #define    r_height            r8
  54.  
  55. #define    r_dstStride            r31
  56. #define    r_srcStride            r30
  57. #define    r_bytes                r29
  58. #define    r_blocks            r28
  59. #define    r_y                    r27
  60.  
  61.     ASM_BEGIN
  62.  
  63.     cmplwi    r_width,32
  64.     ble        @small
  65.  
  66.     stw        r27,-20(SP)
  67.     stw        r28,-16(SP)
  68.     stw        r29,-12(SP)
  69.     stw        r30,-8(SP)
  70.     stw        r31,-4(SP)
  71.  
  72.  
  73.     lwz        r9,gBlitPixieProcessorType(RTOC)
  74. #if USE_GENERIC_CACHE
  75.     lwz        r10,gCacheable(RTOC)
  76. #endif
  77.  
  78.     mr        r_bytes,r_width
  79.     mr        r_y,r_height
  80.  
  81.     lha        r9,0(r9)
  82. #if USE_GENERIC_CACHE
  83.     lbz        r10,0(r10) 
  84. #endif
  85.  
  86.     sub        r_srcStride,r_srcRowBytes,r_width
  87.     sub        r_dstStride,r_dstRowBytes,r_width
  88.  
  89.     cmplwi    cr5,r9,k601            // PPC 601?
  90. #if USE_GENERIC_CACHE
  91.     cmplwi    cr1,r10,0            // cacheable?
  92. #endif
  93.  
  94.     rlwinm    r9,r3,0,30,31        // src & 3
  95.     rlwinm    r10,r4,0,30,31        // dst & 3
  96.     cmplw    cr6,r9,r10            // aligned?
  97.  
  98.     bne        cr5,@aligned
  99.     bne        cr6,@unaligned
  100.  
  101. @aligned:
  102.  
  103.     // ALIGNED/DOUBLES ------------------------------------------------------------------
  104.  
  105.         neg        r0,r4
  106.         rlwinm    r0,r0,0,27,31
  107.         sub        r_bytes,r_bytes,r0
  108.  
  109.         subi    r3,r3,8
  110.         subi    r4,r4,8
  111.  
  112.         rlwinm.  r_blocks,r_bytes,27,5,31
  113.         rlwinm   r_bytes,r_bytes,0,27,31
  114.  
  115.     #define    FLAG_BLOCKS            20
  116. //    #define    FLAG_FREE            21    // note: free for use
  117.  
  118.     #define    FLAG_PRE1            26    
  119.     #define    FLAG_PRE2            25    
  120.     #define    FLAG_PRE4            24    
  121.     #define    FLAG_PRE8            23    
  122.     #define    FLAG_PRE16            22        
  123.  
  124.     #define    FLAG_POST1            31
  125.     #define    FLAG_POST2            30
  126.     #define    FLAG_POST4            29
  127.     #define    FLAG_POST8            28    
  128.     #define    FLAG_POST16            27
  129.  
  130.         rlwinm    r0,r0,27-FLAG_PRE16,FLAG_PRE16,FLAG_PRE1
  131.         rlwimi    r0,r_bytes,27-FLAG_POST16,FLAG_POST16,FLAG_POST1
  132.         mtcrf    0x07,r0            // cr5 | cr6 | cr7
  133.         crnor    FLAG_BLOCKS,0*CR_NO + CR_EQ,0*CR_NO + CR_EQ
  134.         
  135.     @alignrowloop:
  136.  
  137.         mtctr    r_blocks
  138.             
  139.             // copy pre-block
  140.         bc        IF_NOT,FLAG_PRE1,@skip_pre1
  141.  
  142.         lbz        r0,8(r3)
  143.         addi    r3,r3,1
  144.         stb        r0,8(r4)
  145.         addi    r4,r4,1
  146.         
  147.     @skip_pre1:
  148.         bc        IF_NOT,FLAG_PRE2,@skip_pre2
  149.  
  150.         lhz        r0,8(r3)
  151.         addi    r3,r3,2
  152.         sth        r0,8(r4)
  153.         addi    r4,r4,2
  154.  
  155.     @skip_pre2:
  156.         bc        IF_NOT,FLAG_PRE4,@skip_pre4
  157.  
  158.         lwz        r0,8(r3)
  159.         addi    r3,r3,4
  160.         stw        r0,8(r4)
  161.         addi    r4,r4,4
  162.  
  163.     @skip_pre4:
  164.         bc        IF_NOT,FLAG_PRE8,@skip_pre8
  165.  
  166.         lfd        fp0,8(r3)
  167.         addi    r3,r3,8
  168.         stfd    fp0,8(r4)
  169.         addi    r4,r4,8
  170.  
  171.     @skip_pre8:
  172.         bc        IF_NOT,FLAG_PRE16,@skip_pre16
  173.         
  174.         lfd        fp1,8(r3)
  175.         lfd        fp2,16(r3)
  176.         addi    r3,r3,16
  177.         stfd    fp1,8(r4)
  178.         stfd    fp2,16(r4)
  179.         addi    r4,r4,16
  180.  
  181.     @skip_pre16:
  182.  
  183.             // copy blocks
  184.         bc        IF_NOT,FLAG_BLOCKS,@skipalignblockloop
  185.         li        r0,8
  186.         
  187.     @alignblockloop:
  188.         lfd        fp1,8(r3)
  189.         lfd        fp2,16(r3)
  190.         lfd        fp3,24(r3)
  191.         lfdu    fp4,32(r3)
  192.  
  193.     #if USE_GENERIC_CACHE
  194.         beq        cr1,@no_cache1
  195.         dcbz    r4,r0
  196.         dcbt    r3,r0
  197.     @no_cache1:
  198.     #endif
  199.     
  200.         stfd    fp1,8(r4)
  201.         stfd    fp2,16(r4)
  202.         stfd    fp3,24(r4)
  203.         stfdu    fp4,32(r4)
  204.         
  205.         bdnz    @alignblockloop
  206.     @skipalignblockloop:
  207.  
  208.         subic.   r_y,r_y,1
  209.         
  210.             // copy post-block
  211.         bc        IF_NOT,FLAG_POST16,@skip_post16
  212.         
  213.         lfd        fp1,8(r3)
  214.         lfd        fp2,16(r3)
  215.         addi    r3,r3,16
  216.         stfd    fp1,8(r4)
  217.         stfd    fp2,16(r4)
  218.         addi    r4,r4,16
  219.  
  220.     @skip_post16:
  221.         bc        IF_NOT,FLAG_POST8,@skip_post8
  222.  
  223.         lfd        fp0,8(r3)
  224.         addi    r3,r3,8
  225.         stfd    fp0,8(r4)
  226.         addi    r4,r4,8
  227.  
  228.     @skip_post8:
  229.         bc        IF_NOT,FLAG_POST4,@skip_post4
  230.  
  231.         lwz        r0,8(r3)
  232.         addi    r3,r3,4
  233.         stw        r0,8(r4)
  234.         addi    r4,r4,4
  235.  
  236.     @skip_post4:
  237.         bc        IF_NOT,FLAG_POST2,@skip_post2
  238.  
  239.         lhz        r0,8(r3)
  240.         addi    r3,r3,2
  241.         sth        r0,8(r4)
  242.         addi    r4,r4,2
  243.  
  244.     @skip_post2:
  245.         bc        IF_NOT,FLAG_POST1,@skip_post1
  246.  
  247.         lbz        r0,8(r3)
  248.         addi    r3,r3,1
  249.         stb        r0,8(r4)
  250.         addi    r4,r4,1
  251.         
  252.     @skip_post1:
  253.  
  254.         add        r3,r3,r_srcStride
  255.         add        r4,r4,r_dstStride
  256.     
  257.     bne            @alignrowloop
  258.  
  259.     b            @end
  260.  
  261. @unaligned:
  262.  
  263.     // UNALIGNED ------------------------------------------------------------------------
  264.  
  265.     rlwinm        r_blocks,r_bytes,27,5,31
  266.     rlwinm        r_bytes,r_bytes,0,27,31
  267.     li            r0,32
  268.  
  269.     cmplwi        cr5,r_blocks,0
  270.     cmplwi        cr6,r_bytes,0
  271.     mtxer        r_bytes
  272.  
  273.     subi        r3,r3,32
  274.     subi        r4,r4,32
  275.  
  276. @unalignrowloop:
  277.  
  278.         beq         cr5,@skipunalignblockloop
  279.         mtctr     r_blocks
  280.  
  281.     @unalignblockloop:    
  282.         lwzu     r5,32(r3)
  283.         lwz      r6,4(r3)
  284.         lwz      r7,8(r3)
  285.         lwz      r8,12(r3)
  286.         lwz      r9,16(r3)
  287.         lwz      r10,20(r3)
  288.         lwz      r11,24(r3)
  289.         lwz      r12,28(r3)
  290.         
  291.     #if USE_GENERIC_CACHE
  292.         beq         cr1,@no_cache2
  293.         dcbz     r4,r0
  294.         dcbt     r3,r0
  295.     @no_cache2:
  296.     #endif
  297.         
  298.         stwu     r5,32(r4)
  299.         stw      r6,4(r4)
  300.         stw      r7,8(r4)
  301.         stw      r8,12(r4)
  302.         stw      r9,16(r4)
  303.         stw      r10,20(r4)
  304.         stw      r11,24(r4)
  305.         stw      r12,28(r4)
  306.         bdnz     @unalignblockloop
  307.     @skipunalignblockloop:
  308.  
  309.         subic.        r_y,r_y,1
  310.  
  311.         beq        cr6,@skipunalignleftover
  312.         lswx    r5,r3,r0
  313.         add        r3,r3,r_bytes
  314.         stswx    r5,r4,r0
  315.         add        r4,r4,r_bytes
  316.     @skipunalignleftover:
  317.  
  318.         add        r3,r3,r_srcStride
  319.         add        r4,r4,r_dstStride
  320.  
  321.     bne            @unalignrowloop
  322.  
  323. @end:
  324.  
  325.     // END ------------------------------------------------------------------------------
  326.  
  327.     lwz        r27,-20(SP)
  328.     lwz        r28,-16(SP)
  329.     lwz        r29,-12(SP)
  330.     lwz        r30,-8(SP)
  331.     lwz        r31,-4(SP)
  332.     blr
  333.  
  334. @small:
  335.  
  336.     // SMALL ----------------------------------------------------------------------------
  337.     
  338.     mtxer    r_width
  339.     mtctr    r_height
  340.  
  341.     stw        r_srcStride,-8(SP)
  342.     stw        r_dstStride,-4(SP)
  343.  
  344.     mr        r_srcStride,r_srcRowBytes
  345.     mr        r_dstStride,r_dstRowBytes
  346.  
  347. @smallrowloop:
  348.  
  349.     lswx    r5,r0,r3
  350.     add     r3,r3,r_srcStride
  351.     stswx    r5,r0,r4
  352.     add     r4,r4,r_dstStride
  353.  
  354.     bdnz    @smallrowloop
  355.  
  356.     lwz     r_srcStride,-8(SP)
  357.     lwz        r_dstStride,-4(SP)
  358.  
  359.     ASM_END
  360. }
  361.  
  362. #pragma mark *** 680X0 asm:
  363. #elif USE_68K_ASSEMBLY
  364.  
  365. ///--------------------------------------------------------------------------------------
  366. //    BlitPixieRect
  367. ///--------------------------------------------------------------------------------------
  368.  
  369. //    NOTE:    assumes bytes, rows > 0 (otherwise overflow)
  370.  
  371. #define SMALL            32        // maximum byte width for small blits
  372.  
  373. //    the 68k blitter is actually 3 in 1 :
  374. //    • if on a '040 and properly aligned, it uses MOVE16 instructions
  375. //      otherwise it uses normal MOVE.L instructions:
  376. //    • a main blitter, which uses "Duff's Device" to unroll the loops
  377. //    • a simplified blitter, with less setup overhead for small blits
  378.  
  379. ASM_FUNC void BlitPixieRect(
  380.     unsigned char *srcPixelP,        
  381.     unsigned char *dstPixelP,            
  382.     unsigned long srcOffset,        
  383.     unsigned long dstOffset,
  384.     unsigned short numBytesPerRow,    
  385.     unsigned short rowsToCopy)        
  386. {
  387.     #define D_srcBytes    D2
  388.     #define D_dstBytes    D3
  389.     #define D_bytes        D4
  390.     #define D_y            D5
  391.     #define D_align        D6
  392.  
  393.     ASM_BEGIN
  394.  
  395.     MOVEM.L      D3-D6/A2,-(SP)
  396.  
  397.     MOVEM.L      srcPixelP,A0-A1
  398.     MOVEM.L   srcOffset,D2-D3
  399.     MOVEM.W   numBytesPerRow,D4-D5
  400.  
  401.     EXT.L      D_bytes
  402.     CMPI.W    ASM_NUM(SMALL),D_bytes
  403.     BCS            @small        // big enough ?
  404.  
  405.         // check for proper processor
  406.     CMP.W      #k68040,gBlitPixieProcessorType
  407.     BNE          @not68040
  408.  
  409.         // check for proper alignment
  410.     MOVE.W      A0,D0
  411.     MOVE.W      A1,D1
  412.     ANDI.W      #0x0F,D0
  413.     ANDI.W      #0x0F,D1
  414.     CMP.W     D0,D1
  415.     BNE       @not68040        // aligned to same 16-bit ?
  416.     OR.W      D1,D0
  417.     ANDI.W      #0x03,D0
  418.     BNE       @not68040        // aligned to word ?
  419.     MOVE.W      D_srcBytes,D0
  420.     OR.W      D_dstBytes,D0
  421.     ANDI.W      #0x0F,D0
  422.     BNE       @not68040        // rowBytes aligned to 16-bit ?
  423.     MOVE.W      D_bytes,D0
  424.     ANDI.W      #0x03,D0
  425.     BNE            @not68040        // whole words ?
  426.  
  427. @do68040:
  428.  
  429.     // MOVE16 ---------------------------------------------------------------------------
  430.  
  431.     MOVEQ     #15,D0
  432.      CLR.L     D1
  433.  
  434.     SUB.L      D_bytes,D_srcBytes
  435.     SUB.L      D_bytes,D_dstBytes
  436.  
  437.      MOVE.W    A1,D_align        //    align words (0-3)
  438.      NEG.W     D_align
  439.      AND.W     D0,D_align
  440.     SUB.W      D_align,D_bytes
  441.     LSR.W       #2,D_align            
  442.  
  443.      MOVE.W    D_bytes,D1
  444.     LSR.W     #4,D1
  445.     AND.W      D0,D1
  446.     LSL.W      #2,D1                //    * sizeof("MOVE16 (A0)+,(A1)+")
  447.     LEA          @loopend16,A2
  448.     SUBA.L      D1,A2    
  449.     MOVE.W    D_bytes,D1
  450.     LSR.W       #8,D1
  451.  
  452.     LSR.W       #2,D_bytes        //    leftover words (0-3)
  453.     ANDI.W    #3,D_bytes
  454.     
  455. @rowloop16:
  456.  
  457.              // aligning loop
  458.          MOVE.W    D_align,D0
  459.          BRA.S    @prewordloopend16
  460.        @prewordloopstart16:    
  461.            MOVE.L    (A0)+,(A1)+
  462.      @prewordloopend16:    
  463.            DBRA    D0,@prewordloopstart16
  464.  
  465.             // main block copy loop
  466.         MOVE.W    D1,D0
  467.            JMP        (A2)
  468.    @loopstart16:
  469.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  470.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  471.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  472.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  473.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  474.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  475.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  476.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  477.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  478.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  479.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  480.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  481.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  482.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  483.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  484.     /*    MOVE16    (A0)+,(A1)+        */        DC.L    0xF6209000
  485.     @loopend16:
  486.            DBRA    D0,@loopstart16
  487.      
  488.              // left-over words loop
  489.          MOVE.W    D_bytes,D0
  490.          BRA.S    @postwordloopend16
  491.        @postwordloopstart16:    
  492.            MOVE.L    (A0)+,(A1)+
  493.     @postwordloopend16:    
  494.            DBRA    D0,@postwordloopstart16
  495.      
  496.     ADDA.L      D_srcBytes,A0
  497.     ADDA.L      D_dstBytes,A1
  498.  
  499.     SUBQ.W     #1,D_y
  500.     BNE.S      @rowloop16
  501.  
  502.     BRA           @end
  503.     
  504. @not68040:
  505.  
  506.     // MOVE.L ---------------------------------------------------------------------------
  507.  
  508.     MOVEQ     #15,D0
  509.      CLR.L     D1
  510.  
  511.      SUB.L      D_bytes,D_srcBytes
  512.     SUB.L      D_bytes,D_dstBytes
  513.   
  514.      MOVE.W    D_bytes,D1
  515.     LSR.W     #2,D1
  516.     AND.W      D0,D1
  517.     ADD.W      D1,D1            //    * sizeof("MOVE.L (A0)+,(A1)+")
  518.     LEA          @loopend,A2
  519.     SUBA.L      D1,A2    
  520.     MOVE.W    D_bytes,D1
  521.     LSR.W       #6,D1
  522.  
  523.     MOVE.W    D_bytes,D_align
  524.     ANDI.W      #2,D_align
  525.     ANDI.W    #1,D_bytes
  526.         
  527. @rowloop:
  528.  
  529.             // main block copy loop
  530.         MOVE.W    D1,D0
  531.            JMP        (A2)
  532.    @loopstart:
  533.         MOVE.L    (A0)+,(A1)+
  534.         MOVE.L     (A0)+,(A1)+
  535.         MOVE.L    (A0)+,(A1)+
  536.         MOVE.L     (A0)+,(A1)+
  537.         MOVE.L    (A0)+,(A1)+
  538.         MOVE.L    (A0)+,(A1)+
  539.         MOVE.L    (A0)+,(A1)+
  540.         MOVE.L     (A0)+,(A1)+
  541.         MOVE.L    (A0)+,(A1)+
  542.         MOVE.L    (A0)+,(A1)+
  543.         MOVE.L     (A0)+,(A1)+
  544.         MOVE.L    (A0)+,(A1)+
  545.         MOVE.L    (A0)+,(A1)+
  546.         MOVE.L    (A0)+,(A1)+
  547.         MOVE.L     (A0)+,(A1)+
  548.         MOVE.L    (A0)+,(A1)+
  549.     @loopend:
  550.            DBRA    D0,@loopstart
  551.  
  552.               // do left-over bytes
  553.         TST.W    D_align
  554.         BEQ.S    @skipword
  555.         MOVE.W    (A0)+,(A1)+
  556.       @skipword:
  557.         TST.W    D_bytes
  558.           BEQ.S    @skipbyte
  559.           MOVE.B    (A0)+,(A1)+
  560.       @skipbyte:
  561.      
  562.     ADDA.L      D_srcBytes,A0
  563.     ADDA.L      D_dstBytes,A1
  564.  
  565.     SUBQ.W     #1,D_y
  566.     BNE.S      @rowloop
  567.  
  568.     BRA        @end
  569.     
  570. @small:
  571.  
  572.     // SMALL ----------------------------------------------------------------------------
  573.  
  574.     SUB.L      D_bytes,D_srcBytes
  575.     SUB.L      D_bytes,D_dstBytes
  576.  
  577.     MOVE.W    D_bytes,D1
  578.     LSR.W     #2,D1
  579.     MOVE.W    D_bytes,D_align
  580.     ANDI.W      #2,D_align
  581.     ANDI.W    #1,D_bytes
  582.  
  583. @smallrowloop:
  584.  
  585.         // words loop
  586.     MOVE.W    D1,D0
  587.     BRA.S    @smallwordloopend
  588. @smallwordloopstart:    
  589.     MOVE.L    (A0)+,(A1)+
  590. @smallwordloopend:    
  591.     DBRA    D0,@smallwordloopstart
  592.  
  593.         // do left-over bytes
  594.     TST.W    D_align
  595.     BEQ.S    @smallskipword
  596.     MOVE.W    (A0)+,(A1)+
  597. @smallskipword:
  598.     TST.W    D_bytes
  599.     BEQ.S    @smallskipbyte
  600.     MOVE.B    (A0)+,(A1)+
  601. @smallskipbyte:
  602.  
  603.     ADDA.L     D_srcBytes,A0
  604.     ADDA.L     D_dstBytes,A1
  605.  
  606.     SUBQ.W     #1,D_y
  607.     BNE.S      @smallrowloop
  608.  
  609. @end:
  610.  
  611.     // END ------------------------------------------------------------------------------
  612.  
  613.     MOVEM.L      (SP)+,D3-D6/A2
  614.  
  615.     ASM_END
  616. }
  617.  
  618. #pragma mark *** Generic C:
  619. #elif USE_GENERIC_C
  620.  
  621. ///--------------------------------------------------------------------------------------
  622. //    BlitPixieRect
  623. ///--------------------------------------------------------------------------------------
  624.  
  625. void BlitPixieRect(
  626.     unsigned char *srcPixelP,        
  627.     unsigned char *dstPixelP,            
  628.     unsigned long srcOffset,        
  629.     unsigned long dstOffset,
  630.     unsigned short numBytesPerRow,        
  631.     unsigned short rowsToCopy)    
  632. {
  633.     BLITPIXIE_ASSERT( numBytesPerRow > 0 );
  634.     BLITPIXIE_ASSERT( rowsToCopy > 0 );
  635.  
  636.     while ( rowsToCopy-- )
  637.     {
  638.         BlitPixieMemCopy( dstPixelP, srcPixelP, numBytesPerRow );
  639.         srcPixelP += srcOffset;
  640.         dstPixelP += dstOffset;
  641.     }
  642. }
  643.  
  644. #endif
  645.  
  646.